package services

import (
	"context"
	"errors"
	"time"

	"github.com/AiGenApps/goout-server/database"
	"github.com/AiGenApps/goout-server/models"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"golang.org/x/crypto/bcrypt"

	"github.com/AiGenApps/goout-server/utils"
)

const UserCollection = "users"

type UserService struct {
	collection *mongo.Collection
}

func NewUserService() *UserService {
	return &UserService{
		collection: database.GetCollection("goout", UserCollection),
	}
}

func (s *UserService) Register(ctx context.Context, req *models.RegisterRequest) (*models.User, error) {
	// 检查用户名是否已存在
	var existingUser models.User
	err := s.collection.FindOne(ctx, bson.M{"username": req.Username}).Decode(&existingUser)
	if err == nil {
		return nil, errors.New("用户名已存在")
	}
	if err != mongo.ErrNoDocuments {
		return nil, err
	}

	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}

	// 创建新用户
	now := time.Now()
	user := &models.User{
		Username:  req.Username,
		Nickname:  req.Nickname,
		Password:  string(hashedPassword),
		CreatedAt: now,
		UpdatedAt: now,
	}

	// 插入数据库
	result, err := s.collection.InsertOne(ctx, user)
	if err != nil {
		return nil, err
	}

	user.ID = result.InsertedID.(primitive.ObjectID)
	return user, nil
}

func (s *UserService) Login(ctx context.Context, req *models.LoginRequest) (*models.LoginResponse, error) {
	var user models.User
	err := s.collection.FindOne(ctx, bson.M{"username": req.Username}).Decode(&user)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, errors.New("用户名或密码错误")
		}
		return nil, err
	}

	// 验证密码
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
	if err != nil {
		return nil, errors.New("用户名或密码错误")
	}

	// 生成JWT token
	token, err := utils.GenerateToken(user.ID.Hex(), user.Username)
	if err != nil {
		return nil, errors.New("生成token失败")
	}

	return &models.LoginResponse{
		Token:    token,
		Username: user.Username,
		Nickname: user.Nickname,
	}, nil
}

func (s *UserService) GetUserByID(ctx context.Context, userID string, user *models.User) error {
	objectID, err := primitive.ObjectIDFromHex(userID)
	if err != nil {
		return err
	}

	err = s.collection.FindOne(ctx, bson.M{"_id": objectID}).Decode(user)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return errors.New("用户不存在")
		}
		return err
	}

	return nil
}

func (s *UserService) UpdateProfile(ctx context.Context, userID string, req *models.UpdateProfileRequest) error {
	objectID, err := primitive.ObjectIDFromHex(userID)
	if err != nil {
		return err
	}

	// 获取当前用户信息
	var user models.User
	err = s.collection.FindOne(ctx, bson.M{"_id": objectID}).Decode(&user)
	if err != nil {
		return err
	}

	// 准备更新的字段
	update := bson.M{
		"nickname":   req.Nickname,
		"updated_at": time.Now(),
	}

	// 如果提供了主题设置，则更新主题
	if req.Theme != "" {
		update["theme"] = req.Theme
	}

	// 如果提供了密码，则验证旧密码并更新新密码
	if req.OldPassword != "" && req.NewPassword != "" {
		// 验证旧密码
		err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword))
		if err != nil {
			return errors.New("当前密码错误")
		}

		// 加密新密码
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
		if err != nil {
			return err
		}
		update["password"] = string(hashedPassword)
	}

	// 执行更新
	result, err := s.collection.UpdateOne(
		ctx,
		bson.M{"_id": objectID},
		bson.M{"$set": update},
	)

	if err != nil {
		return err
	}

	if result.ModifiedCount == 0 {
		return errors.New("未能更新用户信息")
	}

	return nil
}
